package cn.lingyangwl.agile.system.controller;

import cn.lingyangwl.agile.common.core.config.GlobalProperties;
import cn.lingyangwl.agile.common.security.service.RegisterPermService;
import cn.lingyangwl.agile.common.security.utils.SecurityUtils;
import cn.lingyangwl.agile.model.constants.TreeCons;
import cn.lingyangwl.agile.model.enums.BoolEnum;
import cn.lingyangwl.agile.model.module.auth.LoginUser;
import cn.lingyangwl.agile.ram.ActionType;
import cn.lingyangwl.agile.ram.RamResource;
import cn.lingyangwl.agile.system.assembly.SysMenuAssembly;
import cn.lingyangwl.agile.system.constants.MenuCons;
import cn.lingyangwl.agile.system.manager.SysMenuSceneManager;
import cn.lingyangwl.agile.system.model.entity.SysMenu;
import cn.lingyangwl.agile.system.model.entity.SysMenuRule;
import cn.lingyangwl.agile.system.model.rqrs.menu.*;
import cn.lingyangwl.agile.system.model.rqrs.user.UserPermissionResp;
import cn.lingyangwl.agile.system.service.SysMenuDataRuleService;
import cn.lingyangwl.agile.system.service.SysMenuService;
import cn.lingyangwl.framework.core.response.Resp;
import com.alibaba.fastjson2.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 菜单数据管理
 * @author shenguangyang
 */
@Api(tags = "菜单权限数据管理")
@Validated
@RestController
@RequestMapping("/menu")
public class MenuController {
    @Resource
    private SysMenuService menuService;
    @Resource
    private SysMenuDataRuleService sysMenuDataRuleService;
    @Resource
    private GlobalProperties globalProperties;
    @Resource
    private RegisterPermService registerPermService;
    @Resource
    private SysMenuSceneManager sceneManager;
    @Resource
    private SysMenuAssembly menuAssembly;

    /**
     * 查询所有可用权限
     */
    @GetMapping("/listAllPermissionValue")
    public Resp<List<JSONObject>> listAllPermissionValue() {
        List<JSONObject> resp = new ArrayList<>();
        registerPermService.listAllPermissionValue().forEach(e -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("key", e);
            jsonObject.put("value", e);
            resp.add(jsonObject);
        });
       return Resp.ok(resp);
    }

    /**
     * 查询菜单
     */
    @ApiOperation(value = "查询菜单")
    @RamResource(action = "sys:menu:query", name = "查询菜单", type = ActionType.READ)
    @GetMapping("/get")
    public Resp<SysMenu> get(@RequestParam("id") Long menuId){
        return Resp.ok(menuService.getMenuById(menuId));
    }

    /**
     * 查询菜单
     * 由前端构建菜单树
     */
    @ApiOperation(value = "查询菜单")
    @RamResource(action = "sys:menu:query", name = "查询菜单", type = ActionType.READ)
    @GetMapping("/list")
    public Resp<List<SysMenu>> list(MenuListReq req){
        LoginUser loginUser = SecurityUtils.getLoginUser();
        List<SysMenu> menus = menuService.listMenuData(req, loginUser.getIsTenantOwner(), loginUser.getUserId());
        return Resp.ok(menus);
    }

    /**
     * 获取菜单树
     */
    @GetMapping("/listMenuTree")
    @RamResource(action = "sys:menu:query", name = "查询菜单", type = ActionType.READ)
    public Resp<List<MenuTreeResp>> listMenuTree(MenuListReq req) {
        Long userId = SecurityUtils.getUserId();
        return Resp.ok(menuService.listMenuTree(req, userId, TreeCons.ROOT_PARENT_ID));
    }

    /**
     * 保存菜单
     */
    @ApiOperation(value = "保存菜单")
    @PostMapping("/save")
    @RamResource(action = "sys:menu:save", name = "保存菜单", type = ActionType.WRITE)
    public Resp<?> save(@RequestBody @Validated SysMenu req){
        req.setStatus(BoolEnum.TRUE.getCode());
        return menuService.saveMenu(req) ? Resp.ok() : Resp.fail("保存失败");
    }

    /**
     * 更新菜单
     */
    @ApiOperation(value = "更新菜单")
    @PostMapping("/update")
    @RamResource(action = "sys:menu:update", name = "更新菜单", type = ActionType.WRITE)
    public Resp<?> update(@Validated @RequestBody SysMenu req){
        return menuService.updateMenu(req) ? Resp.ok() : Resp.fail("更新失败");
    }

    /**
     * 删除菜单
     */
    @ApiOperation(value = "删除菜单")
    @RamResource(action = "sys:menu:delete", name = "删除菜单", type = ActionType.WRITE)
    @DeleteMapping("/delete")
    public Resp<?> delete(@RequestParam(value = "id") String menuId){
        return menuService.deleteMenuById(Long.parseLong(menuId)) ? Resp.ok() : Resp.fail("删除失败");
    }

    /**
     * 获取路由信息
     * @param sceneCode 场景标识符
     * @return 路由信息
     */
    @ApiOperation("查询用户拥有的菜单权限和按钮权限")
    @GetMapping("/getUserPermission")
    public Resp<UserPermissionResp> getUserPermission(
            @RequestParam(required = false, name = "sceneCode") String sceneCode
    ) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        List<SysMenu> userMenus = menuService.listLoginUserMenu(loginUser, false);

        List<VueRouterResp> vueRouterRespList = menuService.buildVueRouters(userMenus);
        List<String> codeList = userMenus.stream()
                .filter((menu) -> MenuCons.Type.BUTTON.equals(menu.getMenuType()) && MenuCons.Status.NORMAL.equals(menu.getStatus()))
                .collect(ArrayList::new, (list, menu) -> list.add(menu.getPerms()), ArrayList::addAll);

        List<SysMenu> allMenus = menuService.listMenu();
        List<MenuAllAuthResp> menuAllAuthRespList = allMenus.stream().map(menuAssembly::toAllAuthResp).collect(Collectors.toList());

        UserPermissionResp result = new UserPermissionResp();
        result.setMenu(vueRouterRespList);
        result.setAllAuth(menuAllAuthRespList);
        result.setCodeList(codeList);
        result.setSysSafeMode(globalProperties.getSafeMode());
        return Resp.ok(result);
    }

    /**
     * 查询菜单权限规则数据
     *
     */
    @GetMapping("/listPermissionRule")
    public Resp<List<SysMenuRule>> listPermissionRule(MenuDataRuleListReq req) {
        List<SysMenuRule> permRuleList = sysMenuDataRuleService.listPermissionRule(req);
        return Resp.ok(permRuleList);
    }

    /**
     * 添加菜单权限规则数据
     *
     */
    @PostMapping("/savePermissionRule")
    @RamResource(action = "sys:menuPermRule:save", name = "保存菜单权限规则", type = ActionType.WRITE)
    public Resp<?> savePermissionRule(@RequestBody MenuDataRuleSaveReq req) {
        sysMenuDataRuleService.savePermissionRule(req);
        return Resp.ok();
    }

    /**
     * 更新菜单权限规则数据
     *
     */
    @PostMapping("/updatePermissionRule")
    @RamResource(action = "sys:menuPermRule:update", name = "更新菜单权限规则", type = ActionType.WRITE)
    public Resp<?> updatePermissionRule(@RequestBody SysMenuRule req) {
        sysMenuDataRuleService.updatePermissionRule(req);
        return Resp.ok();
    }

    /**
     * 更新菜单权限规则数据
     *
     */
    @DeleteMapping("/deletePermissionRule")
    @RamResource(action = "sys:menuPermRule:delete", name = "删除菜单权限规则", type = ActionType.WRITE)
    public Resp<?> deletePermissionRule(@RequestParam(name = "id") @NotEmpty(message = "请选择数据规则") String id) {
        sysMenuDataRuleService.deletePermissionRule(id);
        return Resp.ok();
    }

    /**
     * 拷贝菜单
     */
    @PostMapping("/copyMenu")
    @RamResource(action = "sys:menu:copy", name = "复制菜单", type = ActionType.WRITE)
    public Resp<?> copyMenu(@RequestBody @Validated MenuCopyReq req) {
        menuService.copyMenu(req);
        return Resp.ok();
    }

    /**
     * 用于授权功能，查询菜单权限树, 入参为场景的两个参数, 如果都传递了优先使用 sceneId 查询
     * @param sceneCode 场景编码
     * @param sceneId 场景ID
     */
    @GetMapping("/listPermissionTree")
    @RamResource(action = "sys:menu:listMenuPermissionTree", name = "查询菜单权限树", type = ActionType.READ)
    public Resp<MenuPermissionTreeResp> listPermissionTree(@RequestParam(value = "sceneCode", required = false) String sceneCode,
                                                           @RequestParam(value = "sceneId", required = false) Long sceneId,
                                                           @RequestParam(name = "allSceneMenu", defaultValue = "false") Boolean allSceneMenu) {
        if (Objects.isNull(sceneId) && StringUtils.isNotEmpty(sceneCode)) {
            sceneId = sceneManager.getSceneByCode(sceneCode).getId();
        }
        return Resp.ok(menuService.listPermissionTree(sceneId, allSceneMenu));
    }
}